# coding=utf-8
import json,re
import logging

import allure
from jsonpath import jsonpath
from jsonpath_ng.ext import parse
import hashlib
from api.common_api import Common_Api
# from api.client import HttpClient
from common.logger import Logger
from common.utils import Utils

utils = Utils()
class Create_Process(Common_Api):

    @allure.step('获取用户下的流程模板信息')
    def get_user_module_info(self):
        """
        获取用户有权限的模板信息
        """
        url = '/flowcenter/flow/search-flows?_=1622943720842'
        resp = self.send(url,method='get')
        # print(resp.text)
        json_obj = json.loads(resp.text)
        print(f'json_obj={json_obj}')
        return resp

    @allure.step('通过指定的模板，新建流程')
    def process_create(self, module_name='', package_id='', flow_template_id='',proc_id='',full_url = ''):
        """
        使用模板名称或者package_id+flow_template_id创建流程，或proc_id发起草稿流程。优先模板名称，其次proc_id，最后package_id+flow_template_id
        module_name = '分支条件直接打回到发起_监控人100'
        """
        # ***************************获取请求所需参数************************
        if module_name == '' and package_id=='' and flow_template_id=='' and proc_id=='' and full_url=='':
            assert False, f'模板名称:module_name为必传参数，或者package_id和flow_template_id必传'
        if proc_id != '':
            url = f'/flowinstance/process/create?proc_id={proc_id}' # 发起草稿流程，需要proc_id
        elif module_name != '':
            # 根据模板名称，或得模板信息中的package_id，flow_template_id
            resp = self.get_user_module_info()
            json_obj = json.loads(resp.text)
            package_id = jsonpath(json_obj, f'$.data.list[*].flows[?(@.name=="{module_name}")].package_id')[0]
            flow_template_id = jsonpath(json_obj, f'$.data.list[*].flows[?(@.name=="{module_name}")].flow_template_id')[0]
            url = f'/flowinstance/process/create?package_id={package_id}&business_id=&flow_template_id={flow_template_id}&flow_id='
        else:
            url = full_url

        # ***********************发起请求***************************
        self.send(url,method='get') # 没啥用的请求了
        # 接口请求得到params和tplData
        url_params = url.split('?')[1]  # 获取到get的参数字符串
        if full_url !='':
            full_get_process_info_url = full_url.replace('process/create','process/get-process-info')
            resp = self.get_process_info_by_initiate(full_url=full_get_process_info_url)
        else:
            resp = self.get_process_info_by_initiate(url_params)
        return resp

    def get_user_list(self):
        url = '/organization/ou/user-list'
        pass
    # def get_users_by_name(self,name):
    #     url = f'/organization/ou/get-users-by-name?filter_disable=1&pi=1&ps=30&package_id=undefined&name={name}&_=1623814283363'
    #     resp = self.send(url,method='get')
    #     return resp

    def get_approve_options(self):
        url = '/flowinstance/approval/get-approve-options'
        pass

    def get_relation_process(self):
        """
        根据用户获取相关流程
        :return:
        """
        body = {'pageIndex': 1,
                'pageSize':	10,
                'selected_ids':	[]}
        url = '/flowinstance/process/get-relation-process'
        resp = self.send(url,body=body,method='post',X_CSRF_Token=self.csrf_token)
        return resp

    def form_data_reload(self,case_param, open_process_resp='',):
        """
        确认路径前重新获取表单数据
        :param case_param: 用例数据，字典格式，此处用到模板和关联流程的名称
        :param open_process_resp:
        :return:
        """
        if open_process_resp=='':
            process_name = self.parse_params(case_param,'process_name')
            open_process_resp = self.process_create(process_name)
        result = self.get_key_by_process_instance(open_process_resp,'tpldata')
        data_control = self.jsonpath_value(result['tpldata'],'$.form.data_control')
        form_data_main = self.jsonpath_value(result['tpldata'],'$.form.form_data.main')
        form_data_children = self.jsonpath_value(result['tpldata'],'$.form.form_data.children')
        form_data_attachments = self.jsonpath_value(result['tpldata'],'$.form.form_data.attachments')
        form_data_attachmentTypes = self.jsonpath_value(result['tpldata'],'$.form.form_data.attachmentTypes')
        form_data={'main':form_data_main,'children':form_data_children,'attachments':form_data_attachments,'attachmentTypes':form_data_attachmentTypes}
        business_id = self.jsonpath_value(result['tpldata'],'$.ProcessInfo.BusinessGuid')
        proc_id = self.jsonpath_value(result['tpldata'],'$.ProcessInfo.ProcessGuid')
        package_id = self.jsonpath_value(result['tpldata'],'$..packageInfo.id')
        relation_process = self._choose_relation_process(case_param)    # 存在case_param['relation_process']，则返回对应的相关流程
        # 组装完整body
        body = {'package_id':package_id,
                'business_id':business_id,
                'form_data':form_data,
                'data_control':data_control,
                'proc_id':proc_id,
                'relation_process':relation_process}
        url = '/flowinstance/approval/form-data-reload'
        resp = self.send(url, payload=body, method='post', X_CSRF_Token=self.csrf_token)
        return resp

    def _choose_relation_process(self,case_param):
        """
        选择相关流程
        :param case_param: 存在case_param['relation_process']，则返回对应的相关流程
        :return:
        """
        relation_process = []
        # 获取关联流程名称，如果不存在则不获取关联流程,relation_process=['流程名称-001','流程名称-002']
        relation_name = self.parse_params(case_param, 'relation_process', 1)
        if relation_name != None:
            resp = self.get_relation_process()  # 获取用户相关流程请求结果
            for index, name in enumerate(relation_name):
                process: dict = self.jsonpath_value(resp.json(), f'$.data.list[?(@.name=="{name}")]')
                # 添加缺少的2个key
                process['index'] = index + 1
                process['urlPrefix'] = ''
                relation_process.append(process)  # 组装成相关流程的列表
        return relation_process

    def get_initiate_steps(self,initiate_param,open_process_resp='',opinion=''):
        """
        新建流程，并确认流程步骤信息
        :param initiate_param: yml中的参数：{'module_name': '01发起明确路径_自动归档匹配到责任人', 'user': 'admin', 'form_values': [['文本框', '多人并行审批']], 'step_cc_list': ['曾斌', '蒋与杨'], 'branch_names': ['多人并行审批允许调整允许跳过,抄送发起人管理员'], 'step_auditor': [{'step_name': '单人审批允许跳过，抄送发起人', 'auditor': ['李乾芳']}]}
        :param open_process_resp: 如果是草稿或者子流程，传入打开流程的响应
        :param opinion: 发起意见
        :return:
        """
        # 流程模板名称
        module_name = self.parse_params(initiate_param, 'module_name',1)
        # 表单值；form_values=[['申请类型', '1'], ['总裁办是否已批营销计划', '1']]
        form_values = self.parse_params(initiate_param, 'form_values', 1)
        # 更新添加的抄送人信息
        step_cc_list = self.get_cc_list_by_name(initiate_param)
        print(f'模板名称: {module_name}')
        print(f'表单值: {form_values}')
        print(f'step_cc_list={step_cc_list}')
        # 如果没有传打开流程响应，则新建流程
        if open_process_resp=='':
            open_process_resp = self.process_create(module_name)  # 新建流程
        # *************************新建流程后的参数处理***************************
        # 获取发起页面token,params,tpldata
        process_instance_resp = self.get_key_by_process_instance(open_process_resp)
        csrf_token = process_instance_resp['token']
        # 加载当前流程相关用户的组织信息，包括发起人和默认抄送人信息
        process_user_info = self.get_user_orgs(token=csrf_token)
        # # 更新默认抄送人信息。已修改为无需展示默认抄送人，代码注释
        # default_cc = jsonpath(process_user_info.json(), f'$.data.step_cc_list')[0]
        # step_cc_list.extend(default_cc)
        # 用于组装确认步骤的参数
        params = process_instance_resp['params']
        tpldata = process_instance_resp['tpldata']

        # **************************组成get_initiate_steps入参*********************
        # 1、初始化请求入参，将params更新进去-------------------
        param_json = {}
        param_json.update(params)
        # 2、从tpldata获取入参各个部分需要组装的参数---------------
        form_data = {}
        children = self.jsonpath_value(tpldata, '$.form.form_data.children')
        fieldSources = self.jsonpath_value(tpldata, '$.form.form_data.fieldSources')
        main = self.jsonpath_value(tpldata, '$.form.form_data.main')
        attachmentTypes = self.jsonpath_value(tpldata, '$.form.form_data.attachmentTypes')
        form_data.update(children=children, fieldSources=fieldSources, main=main, attachmentTypes=attachmentTypes)
        process_info = {"ProcessDisplayName":self.jsonpath_value(tpldata,'$..ProcessDisplayName'),
                        "ProcessModuleName":self.jsonpath_value(tpldata,'$..ProcessModuleName')}
        attachment_control = self.jsonpath_value(tpldata,'$..attachment_control')
        relation_process = self.jsonpath_value(tpldata,'$..RelationProcessList')
        title = self.jsonpath_value(tpldata,'$..Title')
        monitors = self.jsonpath_value(tpldata,'$..Monitors')
        _prc_name_ = self.jsonpath_value(tpldata,'$..Title')
        # 3、页面表单参数输入，用于走分支条件------------------------
        # form_values = [('申请类型', '1'), ('总裁办是否已批营销计划', '1')]
        if form_values:
            for form in form_values:
                field_code = jsonpath(tpldata,
                                      f'$.form.data_define.main.fields[?(@.name=="{form[0]}")].code')
                print(f'field_code={field_code}')
                main[field_code[0]] = form[1]
        # 4、组织选择，用于根据组织解析责任人------------------------
        # 查询是否有用例传入了组织
        department = initiate_param.get('department')
        if initiate_param.get('department'):
            # 如果传入了组织，则根据组织获取组织id
            org_id = jsonpath(process_user_info.json(), f'$.data.departData[?(@.name_path=="{department}")].org_id')
            # 如果org_id为false，则报错
            if org_id is False:
                logging.error(f'用户不存在组织【{department}】，无法获取组织id')
                assert False, f'用户不存在组织【{department}】，无法获取组织id，请检查！'
        else:
            # 否则默判断是否有默认组织
            default = jsonpath(process_user_info.json(), '$.data.departData[?(@.is_default==1)].name_path')
            # 如果有默认组织，则获取默认组织id
            if default:
                org_id = self.jsonpath_value(process_user_info.json(),
                                             '$.data.departData[?(@.is_default==1)].org_id')
            # 否则获取第一个组织
            else:
                org_id = jsonpath(process_user_info.json(), '$.data.departData[?(@.is_default==0)].org_id')[0]
        param_json['initiater']['initiater_org_id']=org_id

        # 5、将所需参数，组成get_initiate_steps请求的最终入参------------------------
        param_json.update({"opinion": opinion,
                           "step_cc_list": step_cc_list,
                           "form_data":form_data,
                           "process_info":process_info,
                           "attachment_control":attachment_control,
                           "title":title,
                           "monitors":monitors,
                           "relation_process":relation_process,
                           "_prc_name_":_prc_name_,
                           "manual_execution":False})
        self._param = param_json
        print(f"param_json={param_json}")
        # 更新发起组织
        param_json = self.select_department(initiate_param, param_json)
        # **************************组装get_initiate_steps入参完成，发送请求*********************
        url = '/flowinstance/process/get-initiate-steps'
        resp = self.send(url, payload=param_json, method='post', X_CSRF_Token=csrf_token, enable_vtk=1)
        return resp

    @allure.step('选择发起组织')
    def select_department(self,initiate_param,initiate_process_body):
        department = self.parse_params(initiate_param,'department',1)
        print(f'department:{department}')
        if department is not None:
            # 用户组织信息的响应json
            resp_json = self.user_orgs_resp.json()
            # 如果在响应能找到入参传入的组织，则进行update
            if jsonpath(resp_json, f'$.data.departData[?(@.name_path=="{department}")].org_id'):
                org_id = self.jsonpath_value(resp_json, f'$.data.departData[?(@.name_path=="{department}")].org_id')
                name_path = self.jsonpath_value(resp_json,
                                                f'$.data.departData[?(@.name_path=="{department}")].name_path')
                initiate_process_body['initiater']['initiater_org_id'] = org_id
                initiate_process_body['initiater']['initiater_org_name'] = name_path
            else:
                Logger.info(f'参数【department】不存在【{department}】组织')
        return initiate_process_body

    @allure.step('选择步骤分支和责任人后，确认步骤信息，确认提交')
    def initiate_submit(self, initiate_param, initiate_steps_resp='', opinion='',open_process_resp=''):
        """
        确认步骤信息并提交发起新流程
        :param initiate_param: yml中的参数：{'module_name': '01发起明确路径_自动归档匹配到责任人', 'user': 'admin', 'form_values': [['文本框', '多人并行审批']], 'step_cc_list': ['曾斌', '蒋与杨'], 'branch_names': ['多人并行审批允许调整允许跳过,抄送发起人管理员'], 'step_auditor': [{'step_name': '单人审批允许跳过，抄送发起人', 'auditor': ['李乾芳']}]}
        :param opinion: 发起意见
        :return:
        """
        # *********************分支选择步骤*********************
        # 获取确认步骤路径请求且选择好分支后的响应
        # 分支选择；branch_names=[ '多人并行审批允许调整允许跳过,抄送发起人管理员','多人并行审批仅一人通过不允许调整跳过' ] #注意：1.分支步骤名不能重复。2.分支按照顺序填入
        branch_names = self.parse_params(initiate_param, 'branch_names', 1)
        # 是否通过外部传入确认步骤响应信息
        if initiate_steps_resp == '':
            resp_steps = self.get_initiate_steps(initiate_param, open_process_resp, opinion)
        else:
            resp_steps = initiate_steps_resp
        # errorCode不存在为False，需要选分支为list:['30014']，不需要选分支为list:['0']
        errorCode = jsonpath(resp_steps.json(), '$.data.validateResult.errorCode')
        Logger.info(f'确认路径返回errorCode：{errorCode}')
        # 先判断如果errorCode是bool，说明没有errorCode的key，直接跳出if，如果不是bool，再判断是否为30014。最后判断是否传入分支选择列表，否则会抛异常。
        if errorCode is not bool and errorCode[0] == '30014' and branch_names!=None:
            for branch_name in branch_names:
                Logger.info(f'选择分支{branch_name}')
                resp_steps = self.choose_branch_step(resp_steps, self._param, branch_name)
        steps_data = resp_steps.json()

        # *********************步骤责任人选择*********************
        # choose_step_auditor = [{ 'step_name': '单人审批允许跳过，抄送发起人',auditor: [ '李乾芳','胡成龙' ] },{'step_name': '审批步骤2',auditor: [ '张三','李四' ]}
        choose_step_auditor = self.parse_params(initiate_param, 'step_auditor', 1)
        # 是否加急参数，不存在urgent参数或者参数为否，加急为否
        urgent = self.parse_params(initiate_param, 'urgent', 1)
        if urgent is None or urgent=='否':
            process_level=0
        else:
            process_level = 1
        actual_steps = steps_data['data']['actuals']
        actual_steps = self.update_steps_by_auditor(actual_steps, choose_step_auditor)
        print(f"actual_steps={actual_steps}")

        # *********************从tpldata中获取提交请求的部分入参*********************
        title = self.tpldata_json['ProcessInfo']['Title']
        monitors = self.tpldata_json['ProcessInfo']['Monitors']
        attachment_control = self.tpldata_json['form']['attachment_control']
        ProcessDisplayName = self.tpldata_json['ProcessInfo']['ProcessDisplayName']
        ProcessModuleName = self.tpldata_json['ProcessInfo']['ProcessModuleName']
        process_info = {"ProcessDisplayName": ProcessDisplayName, "ProcessModuleName": ProcessModuleName}
        param_create_process = {"title": title, "monitors": monitors, "attachment_control": attachment_control,
                                      "process_info": process_info}

        # ********************组装initiate_process入参*******************
        initiate_process_body = {}
        initiate_process_body.update(self._param)
        initiate_process_body['initiater'].update(
            initiater_company_id=initiate_process_body['initiater']['initiater_org_id'])
        relation_process = self._choose_relation_process(initiate_param)
        initiate_process_body.update(relation_process=relation_process, process_level=process_level, branch_choose=[])
        initiate_process_body.update(actual_steps=actual_steps)
        initiate_process_body.update(param_create_process)
        # # 选择组织,从确认路径处选择组织，进行责任人解析
        # initiate_process_body = self.select_department(initiate_param, initiate_process_body)
        print(f"initiate_process_body={initiate_process_body}")
        # 是否要更新其他参数到入参body中，用于造异常参数
        other_params = self.parse_params(initiate_param,'other_params',1)
        if other_params:    #存在other_params，才进行参数替换
            for other in other_params:
                utils.update_json_by_jsonpath(initiate_process_body,other['jsonpath'],other['value'])
        # ********************组装initiate_process入参完成，执行提交请求*******************
        prc_name = param_create_process['title']
        url=f'/flowinstance/process/initiate?prc_name={prc_name}'
        resp = self.send(url, payload=initiate_process_body, headers={'Content-Type': 'application/json'}, method='post',
                         enable_vtk=1)
        return resp
